package jinyilw.swing.rlaf.utils;

import jinyilw.common.Operator;
import jinyilw.common.SettingTools;
import jinyilw.common.app.AppConfig;
import jinyilw.swing.ColorTools;
import jinyilw.swing.ComponentTools;
import jinyilw.swing.FontTools;
import jinyilw.swing.ResourceManager;
import jinyilw.swing.i18n.ICSetting;
import jinyilw.swing.i18n.IString;
import jinyilw.swing.i18n.LanguageTools;
import jinyilw.swing.icon.LazyScaleIcon;
import jinyilw.swing.image.ImageTools;
import jinyilw.swing.res.LoadClass;
import jinyilw.swing.rlaf.UITools;
import jinyilw.swing.rlaf.theme.RRootPaneSet;
import jinyilw.swing.rlaf.theme.RThemeColor;
import jinyilw.swing.rlaf.theme.UIData;
import jinyilw.swing.rlaf.ui.RFocusManager;
import jinyilw.swing.rlaf.ui.RRootPaneUI;
import jinyilw.swing.rlaf.ui.RSliderUI;
import jinyilw.swing.rlaf.ui.RTitlePane;
import jinyilw.swing.visuals.FlatDialog;
import jinyilw.swing.visuals.FlatFrame;
import jinyilw.swing.visuals.Icomp.ILabel;
import jinyilw.swing.visuals.Icomp.IMenu;
import jinyilw.swing.visuals.Icomp.IMenuItem;
import jinyilw.swing.visuals.Icomp.IPopupMenu;
import jinyilw.swing.visuals.Rcomp.RDialog;
import jinyilw.swing.visuals.Rcomp.RFileChooser;
import jinyilw.swing.visuals.comp.ActScaleImageComp;
import jinyilw.swing.visuals.panel.SimplePalette;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.plaf.RootPaneUI;
import javax.swing.text.JTextComponent;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;

/**
 * @author Jinyi
 */
public class RLafUtils
{
	private static Operator<?> openOperator, resetOperator;
	private static Operator<?> lightOperator, darkOperator, blackOperator;
	private static Operator<?> blurSliderOperator;

	private static SettingDialog settingDialog;
	private static JDialog aboutDialog;
	private static JPopupMenu settingPopupMenu;
	private static Window invokeWindow;

	public static boolean transparentEnable = true;
	public static float universeAlpha;
	public static int universeBright;

	static
	{
		universeAlpha = SettingTools.getDefaultFloat("universeAlpha", 1f);
		universeBright = SettingTools.getDefaultInt("universeBright", 20);
		if (universeAlpha == 1f)
			transparentEnable = false;
		AppConfig.addAppExitingOperator(o -> {
			SettingTools.putDefaultSettingData("themeType",
					UITools.themeType);
			SettingTools.putDefaultSettingData("universeAlpha",
					universeAlpha);
			SettingTools.putDefaultSettingData("universeBright",
					universeBright);
			SettingTools.putDefaultSettingData("imageBlurriness",
					UITools.imageBlurriness);
			ColorTools.putColorToDefaultSettings("themeColor", RThemeColor.themeColor);
		});
	}

	private RLafUtils()
	{
	}

	public static RFocusManager configTextComponent(JTextComponent t)
	{
		t.setOpaque(false);
		t.setSelectionColor(RThemeColor.darkThemeColor);
		t.setSelectedTextColor(RThemeColor.selectedTextColor);
		t.setBorder(RBorderFactory.getTextBorder());
		return new RFocusManager(t);
	}

	public static void paintTextComponent(Graphics g, JTextComponent t,
			boolean isFocus)
	{
		Graphics2D g2d = (Graphics2D) g;
		float al = t.isEnabled() ? 1f : 0.4f;
		g2d.setComposite(ComponentTools.alphaComposite.derive(al));
		g.setColor(RThemeColor.colorSet.transTBGColor);
		g.fillRoundRect(1, 1, t.getWidth() - 2, t.getHeight() - 2, 6, 6);

		g.setColor(isFocus
				? RThemeColor.themeColor
				: RThemeColor.colorSet.borderColor);
		g.drawRoundRect(1, 1, t.getWidth() - 2, t.getHeight() - 2, 6, 6);
	}

	public static void setTransparentEnable(boolean b)
	{
		if (transparentEnable == b)
			return;
		transparentEnable = true;
		for (Window w : Window.getWindows())
		{
			if (w instanceof FlatFrame)
			{
				((FlatFrame) w).setTransparent(b);
				continue;
			}
			if (w instanceof FlatDialog)
			{
				((FlatDialog) w).setTransparent(b);
				continue;
			}
			RootPaneUI rUI = null;
			if (w instanceof JFrame)
				rUI = ((JFrame) w).getRootPane().getUI();
			else if (w instanceof JDialog)
				rUI = ((JDialog) w).getRootPane().getUI();
			if (rUI instanceof RRootPaneUI)
				((RRootPaneUI) rUI).setTransparent(b);
		}
		transparentEnable = b;
	}

	public static void updateWindowBackground()
	{
		if (transparentEnable)
			return;
		for (Window w : Window.getWindows())
		{
			boolean transparent = false, resizable = false;
			RootPaneUI rUI = null;
			if (w instanceof JFrame)
			{
				JFrame frame = (JFrame) w;
				resizable = frame.isResizable();
				rUI = frame.getRootPane().getUI();
			} else if (w instanceof JDialog)
			{
				JDialog dialog = (JDialog) w;
				resizable = dialog.isResizable();
				rUI = dialog.getRootPane().getUI();
			}
			if (rUI instanceof RRootPaneUI)
				transparent = ((RRootPaneUI) rUI).isTransparent();
			if (resizable && !transparent)
				w.setBackground(RRootPaneSet.getRootPaneSet().bgColor);
		}
	}

	public static void configSettingMenu(Container c)
	{
		c.add(createSetAction());
	}

	private static ActScaleImageComp createSetAction()
	{
		// UIData uiData = UIData.getDefaultUIData();
		ActScaleImageComp setComp = new ActScaleImageComp(
				(LazyScaleIcon) UIData.getDefaultUIData().frameUI.setIcon);
		if (settingPopupMenu == null)
			createSettingPopupMenu();
		setComp.addClickOperator(o -> {
			settingPopupMenu.show(setComp, 0, setComp.getHeight());
			invokeWindow = SwingUtilities.getWindowAncestor(setComp);
		});
		return setComp;
	}

	private static synchronized void createSettingPopupMenu()
	{
		final JPopupMenu popup = new IPopupMenu();
		final IMenuItem light = new IMenuItem(
				new ICSetting("lightString", "浅色主题", "Light theme"));
		final IMenuItem dark = new IMenuItem(
				new ICSetting("darkString", "深色主题", "Dark theme"));
		//		final IMenuItem black = new IMenuItem(
		//				new ICSetting("blackString", "黑色主题", "Black theme"));
		final IMenu setBack = new IMenu(
				new ICSetting("setBack", "背景设置", "Set background"));
		final IMenuItem open = new IMenuItem(
				new ICSetting("chooseBack", "选择背景", "Choose Background"));
		final IMenuItem reset = new IMenuItem(
				new ICSetting("resetBack", "恢复默认", "Reset Background"));
		final IMenuItem advset = new IMenuItem(
				new ICSetting("advancedSet", "高级设置", "Advanced settings"));
		setBack.add(open);
		setBack.add(reset);
		setBack.add(advset);

		final IMenu setFont = new IMenu(
				new ICSetting("setFont", "字体设置", "Set font"));
		final IMenuItem openFont = new IMenuItem(
				new ICSetting("openFont", "选择字体", "Choose font"));
		final IMenuItem resetFont = new IMenuItem(
				new ICSetting("resetFont", "恢复默认", "Reset font"));
		final IMenuItem systemFont = new IMenuItem(
				new ICSetting("systemFont", "系统字体", "More system fonts"));
		setFont.add(openFont);
		setFont.add(resetFont);
		// setFont.add(systemFont);

		final IMenuItem about = new IMenuItem(
				new ICSetting("aboutString", "关于主题", "About Theme"));

		IMenu setLanguage = getSetLanguage();
		lightOperator = o -> UITools.setLightTheme();
		darkOperator = o -> UITools.setDarkTheme();
		blackOperator = o -> UITools.setBlackTheme();
		openOperator = new Operator<>()
		{
			final IString title = new IString("setBack.choose", "背景设置-选择图片文件",
					"Set background - choose picture");

			@Override
			public void operate(Object o)
			{
				RFileChooser chooser = ImageTools.getPictureOpenChooser(
						"bgImages", title.getI18nString());
				UITools.setBGImageFile(
						chooser.openAndGetOpenFile(invokeWindow));
			}
		};
		resetOperator = o -> UITools.resetBGImage();
		ActionListener listener = new ActionListener()
		{
			RFileChooser fontFileChooser;
			@Override
			public void actionPerformed(ActionEvent e)
			{
				// String action = e.getActionCommand();
				Object o = e.getSource();
				if (o == light)
				{
					if (lightOperator != null)
						lightOperator.run();
				} else if (o == dark)
				{
					if (darkOperator != null)
						darkOperator.run();
				}
				//				else if (o == black)
				//				{
				//					if (blackOperator != null)
				//						blackOperator.operate(null);
				//				}
				else if (o == open)
				{
					if (openOperator != null)
						openOperator.run();
				} else if (o == reset)
				{
					if (resetOperator != null)
						resetOperator.run();
				} else if (o == advset)
				{
					if (settingDialog == null
							|| settingDialog.getOwner() != invokeWindow)
						settingDialog = new SettingDialog(invokeWindow);
					settingDialog.setVisible(true);
				} else if (o == openFont)
				{
					if (fontFileChooser == null)
						fontFileChooser = new RFileChooser("font", "ttf",
								"选择字体文件");
					File fontFile = fontFileChooser
							.openAndGetOpenFile(invokeWindow);
					if (fontFile != null)
						FontTools.changeDefaultFont(fontFile);
				} else if (o == resetFont)
				{
					FontTools.resetDefaultFont();
				}
			}
		};
		light.addActionListener(listener);
		dark.addActionListener(listener);
		//black.addActionListener(listener);
		open.addActionListener(listener);
		reset.addActionListener(listener);
		advset.addActionListener(listener);
		openFont.addActionListener(listener);
		resetFont.addActionListener(listener);
		systemFont.addActionListener(listener);
		popup.add(light);
		popup.add(dark);
		//		popup.add(black);
		popup.addSeparator();
		popup.add(setBack);
		popup.addSeparator();
		popup.add(setFont);
		popup.addSeparator();
		if (LanguageTools.languageSettingEnable)
		{
			popup.add(setLanguage);
			popup.addSeparator();
		}
		popup.add(about);
		about.addActionListener(e -> showAboutDialog(invokeWindow));
		settingPopupMenu = popup;
	}
	private static IMenu getSetLanguage()
	{
		IMenu setLanguage = null;
		if (LanguageTools.languageSettingEnable)
		{
			setLanguage = new IMenu(
					new ICSetting("setLanguage", "语言设置", "Set language"));
			IMenuItem zhSetItem = new IMenuItem(
					new ICSetting("chinese", "中文", "Chinese"));
			IMenuItem enSetItem = new IMenuItem(
					new ICSetting("english", "英文", "English"));
			zhSetItem.addActionListener(e -> LanguageTools.setToChinese());
			enSetItem.addActionListener(e -> LanguageTools.setToEnglish());
			setLanguage.add(zhSetItem);
			setLanguage.add(enSetItem);
		}
		return setLanguage;
	}

	public static void configSettingOperator(Operator<?> lOperator,
			Operator<?> dOperator, Operator<?> bOperator, Operator<?> oOperator,
			Operator<?> rOperator)
	{
		lightOperator = lOperator;
		darkOperator = dOperator;
		blackOperator = bOperator;
		openOperator = oOperator;
		resetOperator = rOperator;
	}

	public static void configBlurSliderOperator(Operator<?> operator)
	{
		blurSliderOperator = operator;
	}

	public static void addToSettingMenu(JMenuItem menuItem)
	{
		if (settingPopupMenu == null || menuItem == null)
			return;
		settingPopupMenu.add(menuItem);
	}

	public static void addToSettingMenu(JMenuItem menuItem,
			final ActionListener listener)
	{
		if (settingPopupMenu == null || menuItem == null)
			return;
		settingPopupMenu.add(menuItem);
		if (listener == null)
			return;
		menuItem.addActionListener(listener);
	}

	public static void addSeparatorToSettingMenu()
	{
		if (settingPopupMenu != null)
		{
			settingPopupMenu.addSeparator();
		}
	}

	public static void restartApplication()
	{
		JFrame frame = getMainFrame();
		RootPaneUI paneUI = null;
		RTitlePane titlePane = null;
		if (frame != null)
			paneUI = frame.getRootPane().getUI();
		if (paneUI instanceof RRootPaneUI)
			titlePane = ((RRootPaneUI) paneUI).getTitlePane();
		if (titlePane != null)
		{
			AppConfig.setRestart(true);
			titlePane.close();
		}
	}

	public static void exitApplication()
	{
		JFrame frame = getMainFrame();
		RootPaneUI paneUI = null;
		RTitlePane titlePane = null;
		if (frame != null)
			paneUI = frame.getRootPane().getUI();
		if (paneUI instanceof RRootPaneUI)
			titlePane = ((RRootPaneUI) paneUI).getTitlePane();
		if (titlePane != null)
			titlePane.close();
	}

	public static void showAboutDialog(Window owner)
	{
		if (aboutDialog == null || aboutDialog.getOwner() != owner)
			aboutDialog = new AboutLafDialog(owner);
		aboutDialog.setVisible(true);
	}

	public static JFrame getMainFrame()
	{
		if (invokeWindow instanceof JFrame)
			return (JFrame) invokeWindow;
		for (Window w : Window.getWindows())
			if (w instanceof JFrame && w.isVisible())
				return (JFrame) w;
		return null;
	}

	public static void setImageBlurriness(int blurriness)
	{
		if (settingDialog != null)
			settingDialog.setImageBlurriness(blurriness);
	}

	static class SettingDialog extends RDialog
	{
		private static final long serialVersionUID = -5073391381922467545L;
		private JSlider alphaSlider, brightSlider, blurSlider;
		private ILabel alphaLabel, brightLabel, blurLabel, themeLabel;
		private SimplePalette palettePanel;

		public SettingDialog(Window window)
		{
			super(window);
			setWindowSymbol(ResourceManager.getResLazyScaleIcon(LoadClass.class, "setting.png"));
			createGUI();
			initText();
			initLayout(window);
		}

		public void setImageBlurriness(int blurriness)
		{
			blurSlider.setValue(blurriness);
			blurSlider.repaint();
		}

		private void createGUI()
		{
			setTitleColor(Color.yellow);

			alphaSlider = new CSlider(JSlider.HORIZONTAL, 0, 100,
					(int) ((1f - universeAlpha) * 100));
			brightSlider = new CSlider(JSlider.HORIZONTAL, 0, 100,
					universeBright);
			blurSlider = new CSlider(JSlider.HORIZONTAL, 0, 100,
					UITools.imageBlurriness);
			alphaLabel = new ILabel();
			brightLabel = new ILabel();
			blurLabel = new ILabel();
			themeLabel = new ILabel();
			alphaSlider.setMajorTickSpacing(20);
			alphaSlider.setMinorTickSpacing(10);
			alphaSlider.setPaintLabels(true);
			alphaSlider.setPaintTicks(true);
			brightSlider.setMajorTickSpacing(20);
			brightSlider.setMinorTickSpacing(10);
			brightSlider.setPaintLabels(true);
			brightSlider.setPaintTicks(true);
			blurSlider.setMajorTickSpacing(20);
			blurSlider.setMinorTickSpacing(10);
			blurSlider.setPaintLabels(true);
			blurSlider.setPaintTicks(true);
			add(alphaSlider);
			add(brightSlider);
			add(alphaLabel);
			add(brightLabel);
			add(blurSlider);
			add(blurLabel);
			add(themeLabel);

			alphaSlider.addChangeListener(e -> {
				universeAlpha = 1f - alphaSlider.getValue() / 100f;
				setTransparentEnable(universeAlpha != 1f);
				for (Window w : Window.getWindows())
					if (w.isVisible())
						w.repaint();
			});

			brightSlider.addChangeListener(e -> {
				universeBright = brightSlider.getValue();
				for (Window w : Window.getWindows())
					if (w.isVisible())
						w.repaint();
			});

			blurSlider.addMouseListener(new MouseAdapter()
			{
				@Override
				public void mouseReleased(MouseEvent e)
				{
					UITools.setImageBlurriness(blurSlider.getValue());
					if (blurSliderOperator != null)
						blurSliderOperator.run();
				}
			});

			palettePanel = new SimplePalette();
			palettePanel.setColumn(6);
			palettePanel.setMoreColorEnabled(true);
			palettePanel.addColorOperator(o -> {
				RThemeColor.setThemeColor(palettePanel.getCurrentColor());
				repaint();
				for (Window w : Window.getWindows())
					if (w.isVisible())
						w.repaint();
			});
			//			Icon icon = ResourceManager.getResLazyRetinalIcon("color.png");
			//			palettePanel.setBorder(
			//					RBorderFactory.createTitleBorder(icon, "设置主题颜色"));
			//			palettePanel.setBorder(
			//					new TitledBorder(null, "设置主题颜色", TitledBorder.CENTER,
			//							TitledBorder.BELOW_TOP, UIData.defaultFont));
			RBorderFactory.setToActiveBorder2(palettePanel, 8);
			add(palettePanel);
		}

		private void initText()
		{
			setTitle(new ICSetting("SettingDialog.title", "高级设置",
					"Advanced Settings"));
			alphaLabel.setText(new ICSetting("SettingDialog.alphaLabel",
					"透 明 度：", "Transparency:"), true);
			brightLabel.setText(new ICSetting("SettingDialog.brightLabel",
					"亮     度：", "Brightness:"));
			blurLabel.setText(new ICSetting("SettingDialog.blurLabel", "模 糊 度：",
					"Fuzziness:"));
			themeLabel.setText(new ICSetting("SettingDialog.themeLabel",
					"主题颜色：", "ThemeColor:"), true);
		}

		private void initLayout(Window w)
		{
			setLayout(null);
			setSize(440, 370);
			setResizable(false);
			setLocationRelativeTo(w);
			alphaLabel.setBounds(20, 10, 90, 30);
			alphaSlider.setBounds(100, 10, 310, 50);
			brightLabel.setBounds(20, 70, 70, 30);
			brightSlider.setBounds(100, 70, 310, 50);
			blurLabel.setBounds(20, 130, 70, 30);
			blurSlider.setBounds(100, 130, 310, 50);
			themeLabel.setBounds(20, 255, 90, 30);
			palettePanel.setBounds(110, 210, 280, 120);
		}
	}

	static class CSlider extends JSlider
	{
		private static final long serialVersionUID = 1299200751252342653L;

		public CSlider(int horizontal, int i, int j, int k)
		{
			super(horizontal, i, j, k);
		}

		@Override
		public void updateUI()
		{
			setUI(new CSliderUI(this));
		}
	}

	static class CSliderUI extends RSliderUI
	{
		public CSliderUI(JSlider b)
		{
			super(b);
		}

		@Override
		protected TrackListener createTrackListener(JSlider slider)
		{
			return new TrackListener();
		}
	}
}
